package reserver

import (
	"context"
	"errors"
	"feng-che.com/server/driver-quiz/internal/dep_db"
	"gitee.com/dromara/carbon/v2"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"mongoDB"
	"sync"
	"time"
)

//基于你的项目结构和需求，我来设计一个 Reserver 结构体
//，用于客户预约车辆使用。这个结构体需要包含预约的基本信息、关联的客户、车辆和服务等信息。

// 预约首先由后台人员排班（创建基本的预约信息），再有客户选择（需要购买了服务）。预约这个包需要依赖以上的包。

type Reserver struct {
	mongoDB.MongoDefaultModelNonID `bson:"basic"`
	ID                             primitive.ObjectID `bson:"_id,omitempty" json:"id"`
	ServiceSoldID                  primitive.ObjectID `bson:"serviceSoldID" json:"serviceSoldID"`
	VehicleID                      primitive.ObjectID `bson:"vehicleID" json:"vehicleID"` //车辆
	CoachID                        primitive.ObjectID `bson:"coachID" json:"coachID"`     // 分配的教练
	ClientID                       primitive.ObjectID `bson:"clientID" json:"clientID"`   // 预约的客户
	// 预约时间段
	StartTime time.Time `bson:"startTime" json:"startTime"` // 预约开始时间
	EndTime   time.Time `bson:"endTime" json:"endTime"`     // 预约结束时间

	// 状态信息
	Status       StatusOfReserver `bson:"status" json:"status"`             // 预约状态: pending/confirmed/completed
	IsCanceled   bool             `bson:"isCanceled" json:"isCanceled"`     // 是否已取消
	CancelReason string           `bson:"cancelReason" json:"cancelReason"` // 取消原因

	// 其他信息
	Notes string `bson:"notes" json:"notes"` // 备注信息

	// 读取用
	VehicleModel     string `bson:"-" json:"vehicleModel"`     // 车辆类型简称
	VehicleCarNumber string `bson:"-" json:"vehicleCarNumber"` // 车辆类型简称
}

type StatusOfReserver string

const (
	Pending   StatusOfReserver = "pending"   // 预约创建，等待客户选择
	Confirmed StatusOfReserver = "confirmed" // 客户选择完成
	Completed StatusOfReserver = "completed" // 预约完成
)

func (r *Reserver) Save(ctx context.Context, updateOptions ...*options.UpdateOptions) (*mongo.UpdateResult, error) {
	if r.ID.IsZero() {
		r.ID = primitive.NewObjectID()
	}
	var opts []*options.UpdateOptions
	if len(updateOptions) > 0 && updateOptions[0] != nil {
		opts = updateOptions
	} else {
		opts = append(opts, options.Update().SetUpsert(true))
	}
	result, err := r.GetCollection().UpdateByID(ctx, r.ID, bson.D{
		{"$set", r},
	}, opts...)
	return result, err
}

func (r *Reserver) Update(ctx context.Context, dataFields *bson.D, opts ...*options.UpdateOptions) error {
	if r.ID.IsZero() {
		return errors.New("没有带入id")
	}
	*dataFields = append(*dataFields, bson.E{Key: "$set", Value: bson.D{*mongoDB.CommonUpdateTimeFieldWithCurrentTime()}})
	_, err := r.GetCollection().UpdateByID(ctx, r.ID, *dataFields, opts...)
	return err
}

func (r *Reserver) Delete(ctx context.Context) error {
	if r.ID.IsZero() {
		return errors.New("没有带入id")
	}
	delFiled := bson.D{}
	fields := mongoDB.CommonDeleteWriteFields()
	for _, i2 := range *fields {
		delFiled = append(delFiled, i2)
	}
	return r.Update(ctx, &bson.D{
		{"$set", delFiled},
	})
}

func (r *Reserver) GetCollectionName() string {
	//TODO implement me
	return "reserver"
}

func (r *Reserver) GetCollection() *mongo.Collection {
	name := r.GetCollectionName()
	return dep_db.ObjectCollection(&name)
}

func (r *Reserver) New() {
	r.Create()
	r.Status = Pending
}

// CreateReserverForOneDay 批量创建一天的排班，需要设置好车辆和日期。这个方法会在保存前检查同一车辆在相同时间段是否已有预约。预约固定为一小时
func (r *Reserver) CreateReserverForOneDay(ctx context.Context) {
	startOfDay := carbon.CreateFromStdTime(r.StartTime).StartOfDay() // 获取预约开始时间的当天0点
	var wg sync.WaitGroup
	for i := 8; i < 20; i++ {
		wg.Add(1)
		go func() {
			start := startOfDay.SetHour(i)
			// 检查同一车辆在相同时间段是否已有预约
			filter := bson.D{
				{"vehicleID", r.VehicleID},
				{"startTime", start.StdTime()},
				{"isCanceled", false},
			}
			newReserver := Reserver{
				VehicleID: r.VehicleID,
			}
			err := newReserver.FindLastOne(ctx, &filter)
			if err == nil { // 如果有预约，跳过
				wg.Done()
				return
			}
			if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
				panic("去重读取错误" + err.Error())
				return
			}
			newReserver.New()
			newReserver.StartTime = start.StdTime()
			newReserver.EndTime = newReserver.StartTime.Add(1 * time.Hour)
			_, err = newReserver.Save(ctx)
			if err != nil {
				panic("批量添加错误" + err.Error())
				return
			}
			wg.Done()
		}()
	}
	wg.Wait()
}
